package net.lzzy.practices.services;


import net.lzzy.practices.entities.Applicant;
import net.lzzy.practices.entities.Course;
import net.lzzy.practices.entities.User;
import net.lzzy.practices.repositories.ApplicantRepository;
import net.lzzy.practices.repositories.CourseRepository;
import net.lzzy.practices.repositories.UserRepository;
import net.lzzy.practices.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.util.List;
import java.util.UUID;

/**
 * @author admin
 */
@Service
public class ApplicantServiceImpl implements ApplicantService{

    private final ApplicantRepository repository;

    private final CourseRepository cRepository;

    private final UserRepository uRepository;

    @Autowired
    public ApplicantServiceImpl(ApplicantRepository repository, CourseRepository cRepository, UserRepository uRepository) {
        this.repository = repository;
        this.cRepository = cRepository;
        this.uRepository = uRepository;
    }

    @Override
    public Applicant apply(UUID studentId, UUID courseId, String token) {
        if (studentId.toString().equals(JwtUtil.verifyToken(token))){
            return null;
        }
        User student = uRepository.findById(studentId).orElse(null);
        if (student == null){
            return null;
        }
        Course course = cRepository.findById(courseId).orElse(null);
        if (course == null){
            return null;
        }
        Applicant applicant = new Applicant();
        applicant.setStudent(student);
        applicant.setCourse(course);
        applicant.setStatus(Applicant.STATUS_APPLYING);
        return repository.save(applicant);
    }

    @Override
    public List<Applicant> getAllCourses(UUID studentId, String token) {
        if (!studentId.toString().equals(JwtUtil.verifyToken(token))){
            return null;
        }
        return repository.findApplicantsByStudentIdEqualsOrderByApplyTimeDesc(studentId);
    }

    @Override
    public List<Applicant> getEnrolledCourses(UUID studentId, String token) {
        if (!studentId.toString().equals(JwtUtil.verifyToken(token))){
            return null;
        }
        return  repository.findApplicantsByStudentIdEqualsAndStatusEqualsOrderByApplyTimeDesc(studentId,Applicant.STATUS_APPROVED);
    }

    @Override
    public List<Applicant> getApplyingCourses(UUID studentId, String token) {
        if (!studentId.toString().equals(JwtUtil.verifyToken(token))){
            return null;
        }
        return repository.findApplicantsByStudentIdEqualsAndStatusEqualsOrderByApplyTimeDesc(studentId,Applicant.STATUS_APPLYING);
    }

    @Override
    public List<Applicant> getDeclinedCourses(UUID studentId, String token) {
        if (!studentId.toString().equals(JwtUtil.verifyToken(token))){
            return null;
        }
        return repository.findApplicantsByStudentIdEqualsAndStatusEqualsOrderByApplyTimeDesc(studentId,Applicant.STATUS_DECLINED);
    }

    private Applicant update(UUID applicantId,String token,int status){
        Applicant applicant = repository.findById(applicantId).orElse(null);
        if (applicant == null){
            return null;
        }
        Course course = applicant.getCourse();
        UUID teacherId = course.getTeacher().getId();
        if (!teacherId.toString().equals(JwtUtil.verifyToken(token))){
            return null;
        }
        applicant.setStatus(status);
        return repository.save(applicant);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Applicant approve(UUID applicantId, String token) {
        Applicant applicant = update(applicantId,token,Applicant.STATUS_APPROVED);
        if (applicant != null){
            Course course = applicant.getCourse();
            User student = applicant.getStudent();
            List<User> students = course.getStudents();
            if (!students.contains(student)){
                students.add(student);
            }
            course.setStudents(students);
            applicant.setCourse(cRepository.save(course));
        }
        return applicant;
    }

    @Override
    public Applicant decline(UUID applicantId, String token) {
        return update(applicantId,token,Applicant.STATUS_DECLINED);
    }

    private List<Applicant> getStudents(UUID courseId, String token,int status) {
        Course course = cRepository.findById(courseId).orElse(null);
        if (course == null){
            return null;
        }
        UUID teacherId = course.getTeacher().getId();
        if (!teacherId.toString().equals(JwtUtil.verifyToken(token))){
            return null;
        }
        return repository.findApplicantsByCourseIdEqualsAndStatusEqualsOrderByApplyTimeDesc(courseId,status);
    }

    @Override
    public List<Applicant> getEnrolledStudents(UUID courseId, String token) {
        return getStudents(courseId,token,Applicant.STATUS_APPROVED);
    }

    @Override
    public List<Applicant> getApplyingStudents(UUID courseId, String token) {
        return getStudents(courseId,token,Applicant.STATUS_APPLYING);
    }

    @Override
    public List<Applicant> getDeclinedStudents(UUID courseId, String token) {
        return getStudents(courseId,token,Applicant.STATUS_DECLINED);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Course removeStudent(UUID courseId, UUID studentId, String token) {
        Course course = cRepository.findById(courseId).orElse(null);
        if (course == null){
            return null;
        }
        UUID teacherId = course.getTeacher().getId();
        if (!teacherId.toString().equals(JwtUtil.verifyToken(token))){
            return null;
        }
        course.getStudents().removeIf(s->s.getId().equals(studentId));
        Applicant applicant = repository.findApplicantByCourseIdAndStudentId(courseId,studentId);
        if (applicant != null){
            applicant.setStatus(Applicant.STATUS_DECLINED);
            repository.save(applicant);
        }
        return cRepository.save(course);
    }



}
//123

